package com.dandandog.framework.faces.model;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.dandandog.framework.common.model.ITree;
import com.dandandog.framework.faces.model.tree.TreeNodeState;
import com.dandandog.framework.faces.utils.TreeUtil;
import com.google.common.collect.Multimap;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;

import java.io.Serializable;
import java.util.List;
import java.util.Optional;

/**
 * @author JohnnyLiu
 */

public abstract class TreeDataModel<T extends ITree> implements Serializable {


    public abstract List<T> queryNode();

    public abstract void handleNode(TreeNode<T> node);


    public TreeNode<T> load(TreeNodeState state) {
        Multimap<String, T> source = TreeUtil.parentMap(queryNode());
        TreeNode<T> root = new DefaultTreeNode<>();
        loadTreeLeaf(root, source, Optional.ofNullable(state).orElse(TreeNodeState.builder().build()));
        return root;
    }

    public final void loadTreeLeaf(TreeNode<T> root, Multimap<String, T> source, TreeNodeState state) {
        resetTreeState(root, state);
        String parentId = Optional.ofNullable(root.getData()).map(ITree::getId).orElse(null);
        for (T t : source.get(parentId)) {
            TreeNode<T> node = new DefaultTreeNode<>(t, root);
            handleNode(node);
            loadTreeLeaf(node, source, state);
        }
    }

    private void resetTreeState(TreeNode<T> root, TreeNodeState state) {
        root.setExpanded(state.isExpand());
        if (ArrayUtil.isNotEmpty(state.getSelected())) {
            for (TreeNode<? extends ITree> node : state.getSelected()) {
                ITree parent = root.getData();
                ITree target = node.getData();
                if (parent == null || target == null) {
                    continue;
                }
                // level 从头匹配
                if (StrUtil.startWith(target.getLevel(), parent.getLevel())) {
                    // level层级上所有节点展开
                    root.setExpanded(true);
                    root.setPartialSelected(true);
                    // level 相等 编辑节点和该节点相同
                    if (StrUtil.equals(parent.getLevel(), target.getLevel())) {
                        if (state.isEdit()) {
                            // 设置节点被选中
                            root.getParent().setSelected(true);
                            // 设置该节点不可选
                            root.setSelectable(false);
                        } else {
                            // 设置节点被选中
                            root.setSelected(true);
                        }
                    }
                }
            }
        }
    }
}
